package com.crayon.utils
{
	import flash.geom.Point;
	
	/**
	 * 扩展的数学函数
	 */
	public class MathUtil
	{
		
		/**
		 * 各种进制之间转换
		 * systemChange(txt,16,10);//16转10
		 * @param	txt    待转换的字符串
		 * @param	radix  转换前的进制
		 * @param	target 转换后的进制
		 * @return
		 */
		public static function systemChange(txt:String, radix:uint, target:uint):String
		{
			var num:Number = parseInt(txt, radix); //把2~32进制转换为10进制 
			return num.toString(target); //把10进制转换为2~32进制 
		}
		
		/**
		 * 精确到小数点后几位
		 * @param	number 元素数值
		 * @param	fractionDigits 小数点后面几位
		 * @return
		 */
		public static function toFixed(number:Number, fractionDigits:Number):Number
		{
			return Math.floor(number * Math.pow(10, fractionDigits)) / Math.pow(10, fractionDigits);
		}
		
		/**
		 * 验证密码强度
		 * @param	sPW 待验证的字符
		 * @return
		 */
		public static function evaluatePwd2(sPW:String):int
		{
			return sPW.replace(/^(?:([a-z])|([A-Z])|([0-9])|(.)){5,}|(.)+$/g, "$1$2$3$4$5").length;
		}
		
		/**
		 * 生成随机数
		 * @param	charLen 生成的长度
		 * @param	type 生成类型  0:：数字+字母（默认） 1：数字  2：字母
		 * @return
		 */
		public static function GenerateCheckCode(charLen:int, type:int = 0):String
		{
			//初始化
			var ran:Number;
			var number:Number;
			var code:String;
			var checkCode:String = "";
			//生成?位随机数  charLen
			for (var i:int = 0; i < charLen; i++)
			{
				//Math.random生成数为类似为0.1234
				ran = Math.random();
				number = Math.round(ran * Math.pow(10, charLen));
				//如果是2的倍数生成一个数字
				
				switch (type)
				{
					case 0: 
						if (number % 2 == 0)
						{
							//"0"的ASCII码是48 
							code = String.fromCharCode(48 + (number % 10));
						}
						else
						{
							code = String.fromCharCode(65 + (number % 26));
						}
						break;
					case 1: 
						code = String.fromCharCode(48 + (number % 10));
						break;
					case 2: 
						code = String.fromCharCode(65 + (number % 26));
						break;
				}
				
				checkCode += code;
			}
			return checkCode;
		}
		
		/**
		 * 数组乘法函数。如果arr1的长度等于arr2的长度则将arr1与arr2对应索引位置上的元素相乘。否则，如果arr2的长度为1，
		 * 则将arr2[0]乘以arr1的所有元素。
		 * @param	arr1 被乘数数组
		 * @param	arr2 乘数数组
		 * @return  相乘结果数组
		 */
		static public function arrMult(arr1:Array, arr2:Array):Array
		{
			var result:Array = [];
			if (arr1.length == arr2.length)
			{
				for (var i:*in arr1)
				{
					result.push(arr1[i] * arr2[i]);
				}
			}
			else if (arr2.length == 1)
			{
				for (var j:*in arr1)
				{
					result.push(arr1[j] * arr2[0]);
				}
			}
			return result;
		}
		
		/**
		 * 获取起始索引到结束索引之间的奇数(包含起始和结束索引点)
		 * @param	startNum 起始索引
		 * @param	endNum   结束索引
		 * @return  奇数数组
		 */
		static public function odd(startNum:int, endNum:int):Array
		{
			var result:Array = [];
			for (var i:int = startNum; i <= endNum; i++)
			{
				if (i == 0)
					continue;
				if (i % 2 != 0)
					result.push(i);
			}
			return result;
		}
		
		/**
		 * 获取起始索引到结束索引之间的偶数(包含起始和结束索引点)
		 * @param	startNum 起始索引
		 * @param	endNum   结束索引
		 * @return  偶数数组
		 */
		static public function even(startNum:int, endNum:int):Array
		{
			var result:Array = [];
			for (var i:int = startNum; i <= endNum; i++)
			{
				if (i == 0)
					continue;
				if (i % 2 == 0)
					result.push(i);
			}
			return result;
		}
		
		/**
		 * 获取起始索引到结束索引之间的质数(包含起始和结束索引点)
		 * @param	startNum 起始索引
		 * @param	endNum   结束索引
		 * @return  质数数组
		 */
		static public function prime(startNum:int, endNum:int):Array
		{
			var result:Array = [];
			if (endNum < 2)
				return result;
			if (startNum <= 0)
				startNum = 2;
			for (var i:int = startNum; i <= endNum; i++)
			{
				var findFlag:Boolean = false;
				if (i == 2)
				{
					result.push(i);
					continue;
				}
				else
				{
					for (var j:int = 2; j <= i - 1; j++)
					{
						if (i % j == 0)
						{
							break;
						}
						else if (j == i - 1)
						{
							findFlag = true;
						}
					}
					if (findFlag)
						result.push(i);
				}
			}
			return result;
		}
		
		/**
		 * 弧度转换成角度。flash中的三角函数都是采用弧度度量，因此，对于习惯用角度来计算三角函数值的同志可能需要此函数
		 * @param	rad 弧度数
		 * @return  角度数值
		 */
		static public function rtoa(rad:Number):Number
		{
			return rad * 180 / Math.PI;
		}
		
		/**
		 * 角度转换成弧度。flash中的三角函数都是采用弧度度量，因此，对于习惯用角度来计算三角函数值的同志可能需要此函数
		 * @param	angle 角度数
		 * @return  弧度数值
		 */
		static public function ator(angle:Number):Number
		{
			return angle * Math.PI / 180;
		}
		
		/**
		 * 根据三角形三边长计算三角形面积(海伦-秦九昭公式)
		 * @param	a 边a的长度
		 * @param	b 边b的长度
		 * @param	c 边c的长度
		 * @return  三角形面积数值
		 */
		static public function angleArea(a:Number, b:Number, c:Number):Number
		{
			var p:Number = 0;
			if (a + b > c && a + c > b && b + c > a)
			{
				p = (a + b + c) / 2;
			}
			return Math.sqrt(p * (p - a) * (p - b) * (p - c));
		}
		
		/**
		 * 将十进制数字转换为二进制表示的字符串(辗转相除取余法)。如果要得到补零格式字符串(如"00010101")，请为size参数
		 * 传递非零整数值。注意：当传递的size小于等于value转换成二进制后尚未补零的字符串的长度时，则不做补零处理，因
		 * 此，可以始终用0 来跳过补零处理。此函数比int、uint和Number类的toString强大之处即在于此。此函数可以按照itoh的
		 * 写法直接使用AS中已有的类方法简化。
		 * @param	value 要转化的十进制数值
		 * @param	size  转化后的二进制字符串的长度
		 * @return  一个二进制形式字符串
		 */
		static public function itob(value:int, size:int):String
		{
			var charArr:Array = [];
			var result:String = "";
			var quotient:Number = value;
			while (true)
			{
				if (quotient == 0)
					break;
				charArr.unshift(quotient % 2);
				quotient = quotient / 2 >> 0;
			}
			for (var i:int = 0; i < charArr.length; i++)
			{
				result += charArr[i];
			}
			if (size > result.length)
			{
				for (var j:int = 0; j < size - result.length; j++)
				{
					result = "0" + result;
				}
			}
			return result;
		}
		
		/**
		 * 将二进制表示的字符串转换为十进制数字
		 * @param	binary 要转换的二进制字符串
		 * @return  十进制数值
		 */
		static public function btoi(binary:String):Number
		{
			var result:Number = 0;
			var numArr:Array = binary.split("");
			while (true)
			{
				if (numArr[0] != "0")
					break;
				numArr.shift();
			}
			var len:int = numArr.length;
			for (var i:int = 0; i < len; i++)
			{
				result += int(numArr[i]) * Math.pow(2, len - i - 1);
			}
			return result;
		}
		
		/**
		 * 将十进制整数转换成16进制表示的字符串。如果要得到补零格式字符串(如"0x00ff00")，请为size参数传递非零整数值。
		 * 注意：当传递的size小于等于value转换成16进制后尚未补零的字符串的长度时，则不做补零处理，因此，可以始终用0
		 * 来跳过补零处理。
		 * @param	value 要转换的16进制数值
		 * @param	size  转化后的16进制字符串的长度
		 * @return  16进制表示的字符串
		 */
		static public function itoh(value:int, size:Number):String
		{
			var result:String = value.toString(16);
			if (size > result.length)
			{
				for (var i:int = 0; i < size - result.length; i++)
				{
					result = "0" + result;
				}
			}
			result = "0x" + result;
			return result;
		}
		
		/**
		 * 求最大值。AS3的Math类中的max函数在求多个参数的最大值时必须要给函数传递多个参数，书写比较麻烦。因此此处将其
		 * 优化为数组参数形式。
		 * @param	numArr 要求最大值的数组
		 * @return  最大值
		 */
		static public function max(numArr:Array):Number
		{
			var result:Number = Number.MIN_VALUE;
			for (var i:int = 0; i < numArr.length; i++)
			{
				if (numArr[i] > result)
				{
					result = numArr[i];
				}
			}
			return result;
		}
		
		/**
		 * 求最小值。AS3的Math类中的min函数在求多个参数的最小值时必须要给函数传递多个参数，书写比较麻烦。因此此处将其
		 * 优化为数组参数形式。
		 * @param	numArr 要求最大值的数组
		 * @return  最小值
		 */
		static public function min(numArr:Array):Number
		{
			var result:Number = Number.MAX_VALUE;
			for (var i:int = 0; i < numArr.length; i++)
			{
				if (numArr[i] < result)
				{
					result = numArr[i];
				}
			}
			return result;
		}
		
		/**
		 * 求根函数(evol是evolution的缩写)。
		 * @param	num       被开放数
		 * @param	exponent  根指数
		 * @return  求根结果
		 */
		static public function evol(num:Number, exponent:int):Number
		{
			return Math.pow(num, 1 / exponent);
		}
		
		/**
		 * 求平均数
		 * @param	numArr 要求平均数的数组
		 * @return  求平均数结果
		 */
		static public function average(numArr:Array):Number
		{
			var result:Number = 0;
			for (var i:int = 0; i < numArr.length; i++)
			{
				result += numArr[i];
			}
			result = result / numArr.length;
			return result;
		}
		
		/**
		 * 求二维平面内两点之间的距离。在设计弹性碰撞运动的相关类时可能会用到此函数
		 * @param	point1 点1
		 * @param	point2 点2
		 * @return  距离值
		 */
		static public function dist(point1:Point, point2:Point):Number
		{
			return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
		}
		
		/**
		 * 计算三维空间内两点的距离
		 * @param	x0
		 * @param	y0
		 * @param	z0
		 * @param	x1
		 * @param	y1
		 * @param	z1
		 * @return  距离值
		 */
		static public function dist3d(x0:Number, y0:Number, z0:Number, x1:Number, y1:Number, z1:Number):Number
		{
			return Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2) + Math.pow(z1 - z0, 2));
		}
		
		/**
		 * 数组求总和
		 * @param	numArr 要求和的数组
		 * @return  总和
		 */
		static public function sum(numArr:Array):Number
		{
			var result:Number = 0;
			for (var i:int = 0; i < numArr.length; i++)
			{
				result += numArr[i];
			}
			return result;
		}
		
		/**
		 * 计算二维向量内积
		 * @param	x0
		 * @param	y0
		 * @param	x1
		 * @param	y1
		 * @return  结果值
		 */
		static public function dot(x0:Number, y0:Number, x1:Number, y1:Number):Number
		{
			return x0 * x1 + y0 * y1;
		}
		
		/**
		 * 计算三维空间向量的内积
		 * @param	x0
		 * @param	y0
		 * @param	z0
		 * @param	x1
		 * @param	y1
		 * @param	z1
		 * @return  结果值
		 */
		static public function dot3d(x0:Number, y0:Number, z0:Number, x1:Number, y1:Number, z1:Number):Number
		{
			return x0 * x1 + y0 * y1 + z0 * z1;
		}
		
		/**
		 * 计算二维向量的外积
		 * @param	x0
		 * @param	y0
		 * @param	x1
		 * @param	y1
		 * @return  外积值
		 */
		static public function cross(x0:Number, y0:Number, x1:Number, y1:Number):Number
		{
			return x0 * y1 - y0 * x1;
		}
		
		/**
		 * 计算三维空间向量的外积
		 * @param	x0
		 * @param	y0
		 * @param	z0
		 * @param	x1
		 * @param	y1
		 * @param	z1
		 * @return  一个包涵属性x,y和z的对象
		 */
		static public function cross3d(x0:Number, y0:Number, z0:Number, x1:Number, y1:Number, z1:Number):Object
		{
			return {x: y0 * z1 - z0 * y1, y: z0 * x1 - x0 * z1, z: x0 * y1 - y0 * x1};
		}
		
		/**
		 * 计算参数 num 的阶乘。零的阶乘为 1 。
		 * <br />
		 * 阶乘：n 的阶乘为 n * (n - 1) * (n - 2) * ... * 2 * 1
		 * @param num 用来计算阶乘的数字。
		 * @return 返回 num 的阶乘。
		 *
		 */
		public static function factorial(num:Number):Number
		{
			if (num == 0)
			{
				return 1;
			}
			
			return num * factorial(num - 1);
		}
		
		/**
		 * 判断一个数是不是奇数。
		 * @param num 待判断的数。
		 * @return 如果是奇数，则返回 true ；是偶数，则返回 false 。
		 *
		 */
		public static function isOdd(num:Number):Boolean
		{
			return Boolean(num & 1);
		}
		
		/**
		 * 返回指定2个非负整数之间的随机数
		 * 注意：若开始数字比结束数字大，则调换两者的值
		 * @param	start	开始(包含)
		 * @param	end		结束(不包含)
		 *  @param	intFlag  是否取整数
		 * @return			返回值
		 */
		public static function random(start:Number, end:Number, intFlag:Boolean = true):Number
		{
			var result:Number = 0;
			var temp:Number;
			if (start > end)
			{
				//因为 start 是包含、end 是不包含，所以这里要加 1
				temp = start + 1;
				start = end + 1;
				end = temp;
			}
			result = (end - start) * Math.random() + start;
			if (intFlag)
				result >>= 0;
			return result;
		}
		
		/**
		 * 将输入的数限制在给定的最大值与最小值之间，用来强制检查输入
		 * @param	value	要检查的输入
		 * @param	min		最小值
		 * @param	max		最大值
		 * @return			返回一个处于 [min, max] 区间内的数
		 */
		public static function constrain(value:Number, min:Number = 0, max:Number = 1):Number
		{
			value = Math.max(value, min);
			value = Math.min(value, max);
			return value;
		}
		
		/**
		 * 将字符串强制转化为浮动变量
		 * @param	string	待转换字符
		 * @return			转换后数字
		 */
		public static function forceParseFloat(string:String):Number
		{
			var value:Number = parseFloat(string);
			return isNaN(value) ? 0 : value; // returns 0 instead of not a number
		}
		
		/**
		 * 将字符串强制转化为整型变量
		 * @param	string	待转换字符
		 * @param	radix	待转换的数字的基数（进制）的整数。 合法值为 2 到 36
		 * @return			转换后数字
		 */
		public static function forceParseInt(string:String, radix:uint = 0):Number
		{
			var value:Number = parseInt(string, radix);
			return isNaN(value) ? 0 : value; // returns 0 instead of not a number
		}
		
		/**
		 * 在数字前填充0
		 * @param	number	需要填充的数字
		 * @param	digits	填充的位数
		 * @return			填充后的数字
		 */
		public static function zeroFill(number:Number, digits:uint):String
		{
			//toFixed返回数字的字符串表示形式，参数表示所需的小数位数
			var length:uint = number.toFixed(0).match(/\d/g).length;
			var prefix:String = "";
			if (length < digits)
			{
				var diff:uint = digits - length;
				for (var i:uint = 0; i < diff; i++)
				{
					prefix += "0";
				}
			}
			return prefix + String(number);
		}
	}
}